// MIT License
// 开源地址：https://gitee.com/co1024/AbcMvc
// Copyright (c) 2021-2023 1024
// Abc.Mvc=Furion+EF+SqlSugar+Pear layui admin.

using Furion.DynamicApiController;
using MiniExcelLibs;

namespace Abc.Application.ApiAdminServices;

/// <summary>
/// 用户管理
/// </summary>
[ApiDescriptionSettings("ApiAdmin", Name = "ApiUser")]
[MaApi(  controller: "ApiUser", controllerDescription: "用户管理", PCode = "API")]
[IgnoreAntiforgeryToken]
public class ApiUserService : IDynamicApiController
{
    private readonly ILogger<ApiUserService> _logger;
    private readonly ISqlSugarClient _db;
    private readonly ISysCacheService _sysCacheService;

    public ApiUserService(ILogger<ApiUserService> logger
       , ISysCacheService sysCacheService
       , ISqlSugarClient db)
    {
        _logger = logger;
        _sysCacheService = sysCacheService;
        _db = db;
    }

    ///// <summary>
    ///// 刷新缓存
    ///// </summary>
    ///// <returns></returns>
    //public override async Task<List<SysUser>> RefreshCacheAsync()
    //{
    //    var datas = await _db.AsQueryable().Includes(r => r.Roles).WithCache().ToListAsync();
    //    return datas;
    //}

    /// <summary>
    /// 新增或更新一条
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [MaPermission(name: "新增或更新一条", actions: "InsertOrUpdate")]
    [UnitOfWork]
    public async Task InsertOrUpdate(ApiUserInput input)
    {
        var roleids = input.RoleIds.ToLongList();
        if (input.Id > 0)
        {
            #region 修改

            //判断账号是否已存在，防止重复添加相同账号
            if (_db.Queryable<SysUser>().Any(o => o.Id != input.Id && o.Account == input.Account))
            {
                throw Oops.Bah($"账号:{input.Account} 已存在");
            }

            var dbentity = await _db.Queryable<SysUser>().Includes(o => o.Roles).FirstAsync(o => o.Id == input.Id);
            input.Adapt(dbentity);
            if (!string.IsNullOrWhiteSpace(input.Pwd))
            {
                dbentity.Pwd = input.Pwd.ToPBKDF2();
            }
            //删除移除了的 用户角色
            if (dbentity.Roles != null && dbentity.Roles.Any())
            {
                var delroleids = dbentity.Roles.Where(o => roleids.All(a => a != o.Id)).Select(a => a.Id).ToList();
                //需要改变仓储，从UserRole中删除
                //await _db.ChangeRepository<SqlSugarRepository<SysUserRole>>().DeleteAsync(o => o.UserId == input.Id && delroleids.Any(a => a == o.RoleId));
                // var deleteuserroles = _repository.Change<SysUserRole>().Where(o => o.UserId == input.Id && delroleids.Contains(o.RoleId));
                await _db.Deleteable<SysUserRole>().Where(o => o.UserId == input.Id && delroleids.Contains(o.RoleId)).ExecuteCommandAsync();
            }

            //新增添加的用户角色
            var adds = new List<SysUserRole>();
            foreach (var roleid in roleids)
            {
                if (dbentity.Roles != null && dbentity.Roles.Any(o => o.Id == roleid)) continue;
                adds.Add(new SysUserRole() { RoleId = roleid, UserId = input.Id.Value });
            }
            await _db.InsertAsync<SysUserRole>(adds);

            await _db.UpdateAsync(dbentity);

            //移除缓存
            await _sysCacheService.RemoveLoginAdminUserCache(input.Id.Value);

            #endregion 修改
        }
        else
        {
            #region 新增

            //判断账号是否已存在，防止重复添加相同账号
            if (_db.Queryable<SysUser>().Any(o => o.Account == input.Account))
            {
                throw Oops.Bah($"账号:{input.Account} 已存在");
            }
            var addentity = input.Adapt<SysUser>();
            //addentity.Roles = new List<SysUserRole>();

            addentity.Pwd = input.Pwd?.ToPBKDF2();
            addentity.IsEnable = true;
            var userid = await _db.InsertRsIdAsync<SysUser>(addentity);
            //新增添加的用户角色
            var adds = new List<SysUserRole>();
            foreach (var roleid in roleids)
            {
                adds.Add(new SysUserRole() { RoleId = roleid, UserId = userid });
            }
            await _db.InsertRsIdAsync<SysUserRole>(adds);

            #endregion 新增
        }
    }

    /// <summary>
    /// 删除一条
    /// </summary>
    /// <param name="id"></param>
    [MaPermission(name: "删除一条", actions: "Delete")]
    public async Task Delete(long id)
    {
        await _db.DeleteByIdAsync<SysUser>(id);
    }

    /// <summary>
    /// 批量删除
    /// </summary>
    /// <param name="ids"></param>
    [MaPermission(name: "批量删除", actions: "BatchDelete")]
    public async Task BatchDelete(string ids)
    {
        await _db.FakeDeleteAsync<SysUser>(ids);
    }

    /// <summary>
    /// 查询一条[跟踪实体]
    /// </summary>
    /// <param name="id"></param>
    [MaPermission(name: "查询一条", actions: "Get")]
    public async Task<ApiUserOut> Get(long id)
    {
        var entity = await _db.Queryable<SysUser>().Includes(o => o.Roles).FirstAsync(o => o.Id == id);

        var result = entity.Adapt<ApiUserOut>();
        result.Roles = entity.Roles?.Adapt<List<ApiRoleOut>>();

        return result;
    }

    /// <summary>
    /// 分页查询
    /// </summary>
    /// <param name="searchQuery"></param>
    /// <returns></returns>
    [MaPermission(name: "分页查询", actions: "GetList")]
    public async Task<PagedList<ApiUserOut>> GetAllByPageToLayui(ApiUserQuery searchQuery)
    {
        var queryable = _db.Queryable<SysUser>()
            .Includes(o => o.Roles)
            .Where(o => o.UserType != UserType.系统维护);
        if (!string.IsNullOrWhiteSpace(searchQuery.KeyWords))
        {
            var kw = searchQuery.KeyWords.ToLower();
            queryable = queryable.Where(o => o.Account.Contains(kw)
                                           || o.Nick.Contains(kw)
                                           || o.Phone.Contains(kw));
        }
        //用户类型
        if (searchQuery.UserType.HasValue)
        {
            //管理员只能查到比自己低的类型用户
            switch (searchQuery.UserType.Value)
            {
                //case UserType.普通用户:
                //    queryable = queryable.Where(o => (o.UserType==UserType.普通用户) && o.UserType == searchQuery.UserType.Value);
                //    break;
                case UserType.超级管理员:
                    queryable = queryable.Where(o => (o.UserType == UserType.超级管理员 || o.UserType == UserType.管理员) && o.UserType == searchQuery.UserType.Value);
                    break;

                case UserType.管理员:
                    queryable = queryable.Where(o => (o.UserType == UserType.管理员) && o.UserType == searchQuery.UserType.Value);
                    break;

                case UserType.系统维护:
                    queryable = queryable.Where(o => o.UserType == searchQuery.UserType.Value);
                    break;

                default:
                    break;
            }
        }
        else
        {
            var userid = App.HttpContext.GetLoginUserId<long>();
            var user = _db.Queryable<SysUser>().First(o => o.Id == userid);
            //管理员只能查到比自己低的类型用户
            switch (user.UserType)
            {
                //case UserType.普通用户:
                //    queryable = queryable.Where(o => (o.UserType==UserType.普通用户));
                //    break;
                case UserType.超级管理员:
                    queryable = queryable.Where(o => (o.UserType == UserType.超级管理员 || o.UserType == UserType.管理员));
                    break;

                case UserType.管理员:
                    queryable = queryable.Where(o => (o.UserType == UserType.管理员));
                    break;

                case UserType.系统维护:
                    //查询全部
                    break;

                default:
                    break;
            }
        }

        var pageResult = queryable.OrderByDescending(o => o.Id);
        RefAsync<int> total = 0;//为什么不用ref 或者 out ,因为他们不支持异步想要真的异步输出这是最优解

        return await pageResult.ToPagedListAsync<SysUser, ApiUserOut>(searchQuery.Page, searchQuery.Limit);
    }

    /// <summary>
    /// 设置状态
    /// </summary>
    /// <param name="id"></param>
    /// <param name="state"></param>
    /// <param name="field">字段名</param>
    /// <returns></returns>
    [MaPermission(name: "设置状态", actions: "SetState")]
    public async Task SetState(long id, bool state, string field)
    {
        var result = await _db.SetStateByIdAsync<SysRole>(id, state, field);
    }

    /// <summary>
    /// 下载Excel列表（保存到内存，然后直接下载）
    /// 参考文档：https://gitee.com/dotnetchina/MiniExcel#excel-%E5%88%97%E5%B1%9E%E6%80%A7-excel-column-attribute-
    /// </summary>
    /// <returns></returns>
    [MaPermission(name: "下载Excel列表", actions: "DownloadExcel")]
    public async Task<IActionResult> DownloadExcel(ApiUserQuery searchquery)
    {
        var pagedlist = await GetAllByPageToLayui(searchquery);

        var memoryStream = new MemoryStream();
        memoryStream.SaveAs(pagedlist);//直接在内存创建然后以流的方式返回
        memoryStream.Seek(0, SeekOrigin.Begin);
        return new FileStreamResult(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
        {
            FileDownloadName = "用户列表.xlsx"
        };
    }

    /// <summary>
    ///下载Excel列表，（使用模板，保存到内存，然后直接下载）
    /// </summary>
    /// <returns></returns>
    [MaPermission(name: "下载Excel列表", actions: "DownloadExcel2")]
    public async Task<IActionResult> DownloadExcel2(ApiUserQuery searchquery)
    {
        var pagedlist = await GetAllByPageToLayui(searchquery);

        string templatePath = $"{App.WebHostEnvironment.WebRootPath}\\Templates\\用户列表模板.xlsx";
        //byte[] bytes = System.IO.File.ReadAllBytes(templatePath);

        //注意：模板填充 外面要封装一层 value,否则会报错的 https://gitee.com/dotnetchina/MiniExcel#2-ienumerable-%E6%95%B0%E6%8D%AE%E5%A1%AB%E5%85%85

        //下面这个rows可以是自己的数据
        var value = new {
            data = pagedlist
        };

        var memoryStream = new MemoryStream();
        memoryStream.SaveAsByTemplate(templatePath, value);
        memoryStream.Seek(0, SeekOrigin.Begin);
        return new FileStreamResult(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
        {
            FileDownloadName = "用模板导出的用户列表.xlsx"
        };
    }
}